from tools9 import (minutes_to_time,calculate_load_time,time_to_minutes,
                    calculate_work_end_time,check_ab_vehicles,parse_shift,
                    safe_parse_list,get_allowed_shifts,calculate_work_start_time,
                    calculate_work_start_time,calculate_unload_done_time,calculate_arrive_time)


# ----------------------
# 排铝卷车次
# ----------------------
def generate_a_schedule(today_tasks, schedule, vehicles, start_window=(360, 720), end_window=(840, 1200)):
    """
    生成铝卷运输调度计划

    Args:
        today_tasks: 当日任务信息
        schedule: 已有的调度计划列表
        vehicles: 可用车辆列表
        start_window: 上午时间窗口 (开始分钟, 结束分钟)
        end_window: 下午时间窗口 (开始分钟, 结束分钟)
        interval: 发车间隔(分钟)

    Returns:
        更新后的调度计划
    """
    # 计算需要运输的铝卷数量
    A_count = max(0,today_tasks['铝卷']['count'] - today_tasks['废铝卷']['count'])
    # 筛选可用的SCANIA和奔驰车辆
    scania_benz = [v for v in vehicles if v['type'] in ['SCANIA', '奔驰'] and not v['used']]
    # 计算需要转移的次数（如果需要运输的铝卷数量超过可用车辆数）
    transfer_count = max(0, A_count - len(scania_benz))

    # 分配车辆
    a_vehicles = scania_benz[:min(A_count, len(scania_benz))]
    a_tasks = []
    used_times = set()
    current_time = start_window[0]

    # 安排上午的运输任务
    first_interval = 30  # 前三趟的间隔
    later_interval = 60  # 后面的间隔
    fixed_fourth_time = 540  # 9:00 = 540分钟

    for i, vehicle in enumerate(a_vehicles):
        if current_time > start_window[1]:
            break
        a_type = '铝卷'
        if i>2 and i<3+today_tasks['铝卷']['discard_drop_count']+today_tasks['铝卷']['discard_count']:
            if i<3+today_tasks['铝卷']['discard_drop_count']:
                a_type = '铝卷（甩废铝）'
            else:
                a_type = '铝卷（废铝）'
        # 特殊处理第四趟
        if i == 3:
            current_time = fixed_fourth_time

        else:
            # 跳过已被占用的时间
            while current_time in used_times and current_time <= start_window[1]:
                current_time += first_interval


        if current_time > start_window[1]:
            break

        time_str = minutes_to_time(current_time)
        vehicle['available_time'] = current_time

        a_tasks.append({
            'type': a_type,
            'time': time_str,
            'vehicle_id': vehicle['id'],
            'is_transfer': False
        })
        used_times.add(current_time)

        # 设置下一个时间间隔
        if i < 3:  # 前三趟之后（索引0,1,2）
            current_time += first_interval
        else:  # 第四趟及之后
            current_time += later_interval
    # 安排下午的转移任务
    for i in range(min(transfer_count, len(a_vehicles))):
        vehicle = a_vehicles[i]
        # 计算转移时间（上午任务后至少9小时）
        morning_time = vehicle['available_time']
        transfer_time = morning_time + 540  # 9小时 = 540分钟

        # 确保转移时间在下午时间窗口内
        if transfer_time < end_window[0]:
            transfer_time = end_window[0]
        elif transfer_time > end_window[1]:
            continue  # 超出时间窗口，跳过

        # 调整到最近的间隔时间点
        transfer_time = ((transfer_time - end_window[0]) // first_interval) * first_interval + end_window[0]

        transfer_time_str = minutes_to_time(transfer_time)
        a_tasks.append({
            'type': '铝卷',
            'time': transfer_time_str,
            'vehicle_id': vehicle['id'],
            'is_transfer': True
        })

    # 将任务添加到调度计划中
    for task in a_tasks:
        selected = next((v for v in vehicles if v['id'] == task['vehicle_id']), None)
        if selected:
            schedule.append({
                'driver_name': selected.get('driver_name', ''),
                'plate_number': selected.get('plate_number', ''),
                'vehicle_id': selected['id'],
                'vehicle_type': selected['type'],
                'departure_time': task['time'],
                'load_time': calculate_load_time(task['time'], '铝卷'),
                'cargo_type': task['type'],
                'is_transfer': '是' if task['is_transfer'] else '否'
            })
            selected['available_time'] = time_to_minutes(task['time'])
            selected['used'] = True
        else:
            print(f"时间为 {task['time']} 的 {task['type']} 无车辆可安排")

    return schedule

def assign_discard_aluminum_tasks(df, vehicle_df, driver_df, assigned_drivers, assigned_vehicles):
    """
    分配废铝任务的司机和车辆
    """
    # 找出运输废铝的车次
    assignment_results=[]  # 初始化排班结果
    # 先筛选废铝
    discard_aluminum_tasks = df[df['cargo_type'] == '废铝/铝卷'].copy()
    for _, task in discard_aluminum_tasks.iterrows():
        id=_
        result = discard_aluminum_task(id,task, vehicle_df, driver_df, assigned_vehicles, assigned_drivers)
        if result is not None:
            assignment_results.append(result)
            assigned_vehicles.add(result['车辆ID'])
            assigned_drivers.add(result['司机姓名'])

    return assignment_results, assigned_drivers, assigned_vehicles

def discard_aluminum_task(id, task, vehicle_df, driver_df, assigned_vehicles, assigned_drivers):
    """
    安排废铝卷任务的司机和车辆
    """
    departure_time = task['departure_time']
    task_shift = parse_shift(departure_time)
    vehicle_type = task['vehicle_type']
    # 先安排司机
    selected_driver = assign_driver_for_discard_aluminum(
        task, task_shift, driver_df, assigned_drivers
    )
    # 再安排车辆
    available_vehicles = vehicle_df[
        (vehicle_df['type'] == vehicle_type) &
        (~vehicle_df['vehicle_id'].isin(assigned_vehicles)) &
        (vehicle_df['region'] == selected_driver['region'])
        ].copy()
    # 出车时间与收车时间间隔大于9小时
    available_vehicles=available_vehicles[time_to_minutes(selected_driver['start_time'])-time_to_minutes(available_vehicles['end_time'])< 900]


    # 计算AB角优先级
    available_vehicles['ab_priority'] = available_vehicles['ab_drivers'].apply(
        lambda x: check_ab_vehicles(x, selected_driver['driver_name'])
    )

    # 按AB角优先级排序（A角优先），然后按司机ID排序
    available_vehicles = available_vehicles.sort_values(
        by=['ab_priority', 'vehicle_id'],
        ascending=[False, True]
    )

    selected_vehicle = available_vehicles.iloc[0]
    # 计算到货时间
    arrive_time = calculate_arrive_time(cargo_type = task['cargo_type'],
                                        dep_time = task['departure_time'],
                                        is_second_special = True if id == 1 else False
                                        )
    # 计算卸货完成时间
    unload_done_time = calculate_unload_done_time(arrive_time = arrive_time,
                                                  cargo_type = task['cargo_type'],
                                                  load_time = task['load_time']
                                                  )
    # 计算收车时间
    end_time = calculate_work_end_time(cargo_type = task['cargo_type'],
                                       unload_done_time = unload_done_time,
                                       region = selected_driver['region'],
                                       is_transfer = task['is_transfer'],
                                       load_time = task['load_time']
                                       )

    if selected_driver is None:
        print(f"没有可用司机用于废铝/铝卷任务: {departure_time}")
        return {
            '发车时间': departure_time,
            '装货时间': task['load_time'],
            '货物类型': '废铝/铝卷',
            '车辆ID': selected_vehicle['vehicle_id'],
            '车辆类型': selected_vehicle['type'],
            '车牌号': selected_vehicle['plate_number'],
            '司机ID': " ",
            '司机姓名': " ",
            '司机所属地区': " 长沙",
            '是否接车': task['is_transfer'],
            '收车时间': end_time
        }
    return {
        '发车时间': departure_time,
        '装货时间': task['load_time'],
        '货物类型': '废铝/铝卷',
        '车辆ID': selected_vehicle['vehicle_id'],
        '车辆类型': selected_vehicle['type'],
        '车牌号': selected_vehicle['plate_number'],
        '司机ID': selected_driver['driver_id'],
        '司机姓名': selected_driver['driver_name'],
        '司机所属地区': selected_driver['region'],
        '是否接车': task['is_transfer'],
        '收车时间': end_time
    }

def assign_driver_for_discard_aluminum(task, task_shift, driver_df, assigned_drivers):
    """
    为废铝任务安排司机
    """
    departure_time = task['departure_time']

    # 筛选符合条件的司机
    eligible_drivers = driver_df[
        (~driver_df['driver_name'].isin(assigned_drivers))].copy()
    if eligible_drivers.empty:
        return None
    eligible_drivers = driver_df[
        (~driver_df['driver_name'].isin(assigned_drivers)) &
        (driver_df['region'] == '长沙')
        ].copy()

    # 计算允许的班次
    eligible_drivers['history_shifts'] = eligible_drivers['last_4days_departure_times'].apply(
        lambda x: [parse_shift(t) for t in safe_parse_list(x) if t is not None]
    )
    eligible_drivers['allowed_shifts'] = eligible_drivers['history_shifts'].apply(get_allowed_shifts)

    # 筛选允许当前班次的司机
    eligible_drivers = eligible_drivers[
        eligible_drivers['allowed_shifts'].apply(lambda x: task_shift in x if x else False)
    ]


    # 筛选车型与司机匹配
    if task['vehicle_type'] != 'SCANIA':
        eligible_drivers = eligible_drivers[eligible_drivers['region'] != '常德']

    # 计算时间优先级
    eligible_drivers['start_time'] = eligible_drivers['region'].apply(
        lambda x:calculate_work_start_time(load_time=task['load_time'],
        departure_time=task['departure_time'],
        region=x,
        cargo_type=task['cargo_type'])
    )
    eligible_drivers['time_priority'] = time_to_minutes(eligible_drivers['start_time']) - time_to_minutes(eligible_drivers['end_time'])

    # 按时间优先级排序，然后按司机ID排序
    eligible_drivers = eligible_drivers.sort_values(
        by=['time_priority', 'driver_id'],
        ascending=[False, True]
    )
    if eligible_drivers.empty:
        return None

    return eligible_drivers.iloc[0]

def assign_changsha_aluminum_roll_tasks(df, driver_df, assigned_drivers):
    # 找出运输下午长沙接车的车次
    assignment_results = []  # 初始化排班结果
    # 先筛选铝卷
    afternoon_aluminum_roll_tasks = df[df['cargo_type'] == '铝卷'].copy()
    afternoon_aluminum_roll_tasks = afternoon_aluminum_roll_tasks[time_to_minutes(afternoon_aluminum_roll_tasks['departure_time']) > 720]
    afternoon_aluminum_roll_tasks = afternoon_aluminum_roll_tasks[afternoon_aluminum_roll_tasks['driver_name'] == '']


    for _, task in afternoon_aluminum_roll_tasks.iterrows():
        result = afternoon_aluminum_roll_task(task, driver_df, assigned_drivers)
        if result is not None:
            assignment_results.append(result)
            assigned_drivers.add(result['司机姓名'])

    return assignment_results, assigned_drivers

def afternoon_aluminum_roll_task(task, driver_df, assigned_drivers):
    """
    安排铝卷任务的司机
    """
    departure_time = task['departure_time']
    task_shift = parse_shift(departure_time)

    # 先安排司机
    selected_driver = assign_driver_for_discard_aluminum(
        task, task_shift, driver_df, assigned_drivers
    )
    if selected_driver is None:
        print(f"没有合适司机用于铝卷任务: {departure_time}")
        return None

    # 计算到货时间
    arrive_time = calculate_arrive_time(cargo_type=task['cargo_type'],
                                        dep_time=task['departure_time'],
                                        is_second_special=True if id == 1 else False
                                        )
    # 计算卸货完成时间
    unload_done_time = calculate_unload_done_time(arrive_time=arrive_time,
                                                  cargo_type=task['cargo_type'],
                                                  load_time=task['load_time']
                                                  )
    # 计算收车时间
    end_time = calculate_work_end_time(cargo_type=task['cargo_type'],
                                       unload_done_time=unload_done_time,
                                       region=selected_driver['region'],
                                       is_transfer=task['is_transfer'],
                                       load_time=task['load_time']
                                       )

    return {
        '发车时间': departure_time,
        '装货时间': task['load_time'],
        '货物类型': '铝卷',
        '车辆ID': " ",
        '车辆类型': " ",
        '车牌号': task['plate_number'],
        '司机ID': selected_driver['driver_id'],
        '司机姓名': selected_driver['driver_name'],
        '司机所属地区': selected_driver['region'],
        '是否接车': task['is_transfer'],
        '收车时间': end_time
    }
